package com.lmbsvn.front.service.impl;

import com.lmbsvn.core.common.BusinessException;
import com.lmbsvn.core.util.EncryptUtils;
import com.lmbsvn.front.constant.Constants;
import com.lmbsvn.front.repository.Hd_svnprojectRepository;
import com.lmbsvn.front.model.*;
import com.lmbsvn.front.service.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

@Service("hd_svnServiceImpl")
public class Hd_svnServiceImpl implements Hd_svnService {
    /**
     * 分隔符
     */
    private static final String SEP = System.getProperty("line.separator");

    @Autowired
    private Hd_svnprojectRepository svnprojectRepository;

    @Autowired
    private Hd_repositoryService repositoryService;//底层

    @Autowired
    private Hd_svnuserService userService;//用户

    @Autowired
    private Hd_svngroupService groupService;//用户组

    @Autowired
    private Hd_svnauthService authService;//权限

    @Autowired
    private Hd_svnprojectusergroupService projectusergroupService;//项目用户用户组关系

    /**
     * 导出到配置文件
     * @param id
     * @throws Exception
     */
    public synchronized void exportConfig(String id) throws Exception {
        this.exportConfig(svnprojectRepository.getOne(id));
    }

    /**
     * 导出到配置文件
     * @param project
     * @throws Exception
     */
    public synchronized void exportConfig(Hd_svnproject project) throws Exception {
        if(project == null){
            return;
        }
        File parent = new File(project.getF_path());
        if (!parent.exists() || !parent.isDirectory()) {
            throw new BusinessException("找不到仓库'"+project.getF_name()+"'路径");
        }
        if(Constants.HTTP.equalsIgnoreCase(project.getF_type())){
            //HTTP(单库) SVNPath
            this.exportHTTP(project);
        }else if(Constants.HTTP_MUTIL.equalsIgnoreCase(project.getF_type())){
            //HTTP(多库) SVNParentPath
            File root = new File(project.getF_path()).getParentFile();
            this.exportHTTPMutil(root);
        }else if(Constants.SVN.equalsIgnoreCase(project.getF_type())){
            //SVN
            this.exportSVN(project);
        }
    }

    /**
     * 导出http(单库)配置信息
     * @param project
     */
    private void exportHTTP(Hd_svnproject project) throws Exception {
        List<Hd_svnuser> userList = userService.getListByProjectId(project.getId());
        Map<String, List<Hd_svnprojectusergroup>> projectGroupUserMap = projectusergroupService.getMapByProjectId(project.getId());
        Map<String, List<Hd_svnauth>> authMap = authService.getMapByProjectId(project.getId());
        this.exportSVNPathConf(project);
        this.exportPasswdHTTP(project, userList);
        this.exportAuthz(project, projectGroupUserMap, authMap);
    }

    /**
     * 输出http(多库)配置信息
     * @param root
     * @throws Exception
     */
    private void exportHTTPMutil(File root) throws Exception {
        String svnRoot = StringUtils.replace(root.getAbsolutePath(), "\\", "/");
        if (!svnRoot.endsWith("/")) {
            svnRoot += "/";
        }

        this.exportSVNParentPathConf(root);
//        this.exportPasswdHTTPMutil(root, usrList);
//        this.exportAuthzHTTPMutil(root, pjGrUsrMap, pjAuthMap);
    }

    /**
     * 导出svn协议配置信息
     * @param project
     */
    private void exportSVN(Hd_svnproject project) throws Exception {
        List<Hd_svnuser> userList = userService.getListByProjectId(project.getId());
        Map<String, List<Hd_svnprojectusergroup>> projectGroupUserMap = projectusergroupService.getMapByProjectId(project.getId());
        Map<String, List<Hd_svnauth>> authMap = authService.getMapByProjectId(project.getId());
        this.exportSvnConf(project);
        this.exportPasswdSVN(project, userList);
        this.exportAuthz(project, projectGroupUserMap, authMap);
    }


    /**
     * 输出http单库方式的httpd.conf文件
     * @param project
     */
    private void exportSVNPathConf(Hd_svnproject project) {
        if (project == null || StringUtils.isBlank(project.getF_name())) {
            return;
        }
        File outFile = new File(project.getF_path(), "/conf/httpd.conf");
        StringBuffer contents = new StringBuffer();
        contents.append("#Include ").append(project.getF_path()).append("/conf/httpd.conf").append(SEP);
        String location = project.getF_name();
        // 例如 http://192.168.1.100/svn/projar/trunk
        if (StringUtils.isNotBlank(project.getF_url()) && project.getF_url().indexOf("//") != -1){
            String svnUrl =repositoryService.parseURL(project.getF_url());
            location = StringUtils.substringAfter(svnUrl, "//");// 192.168.1.100/svn/projar/trunk
            location = StringUtils.substringAfter(location, "/");// svn/projar/trunk
            location = StringUtils.substringBeforeLast(location, "/trunk");
        }
        contents.append("<Location /").append(location).append(">").append(SEP);
        contents.append("DAV svn").append(SEP);
        contents.append("SVNPath ").append(project.getF_path()).append(SEP);
        contents.append("AuthType Basic").append(SEP);
        contents.append("AuthName ").append("\"").append(project.getF_name()).append("\"").append(SEP);
        contents.append("AuthUserFile ").append(project.getF_path()).append("/conf/passwd.http").append(SEP);
        contents.append("AuthzSVNAccessFile ").append(project.getF_path()).append("/conf/authz").append(SEP);
        contents.append("Require valid-user").append(SEP);
        contents.append("</Location>").append(SEP);
        this.write(outFile, contents.toString());
    }

    /**
     * 输出http多库方式的httpd.conf文件
     * @param root
     */
    private void exportSVNParentPathConf(File root) {
        String svnRoot = StringUtils.replace(root.getAbsolutePath(), "\\", "/");
        File outFile = new File(root, "httpd.conf");
        StringBuffer contents = new StringBuffer();
        contents.append("#Include ").append(svnRoot).append("/httpd.conf").append(SEP);
        String location = root.getName();

        contents.append("<Location /").append(location).append("/>").append(SEP);
        contents.append("DAV svn").append(SEP);
        contents.append("SVNListParentPath on").append(SEP);
        contents.append("SVNParentPath ").append(svnRoot).append(SEP);
        contents.append("AuthType Basic").append(SEP);
        contents.append("AuthName ").append("\"").append("Subversion repositories").append("\"").append(SEP);
        contents.append("AuthUserFile ").append(svnRoot).append("/passwd.http").append(SEP);
        contents.append("AuthzSVNAccessFile ").append(svnRoot).append("/authz").append(SEP);
        contents.append("Require valid-user").append(SEP);
        contents.append("</Location>").append(SEP);
        contents.append("RedirectMatch ^(/").append(location).append(")$ $1/").append(SEP);
        this.write(outFile, contents.toString());
    }

    /**
     * 输出http单库方式的密码文件
     * @param project
     * @param userList
     */
    private void exportPasswdHTTP(Hd_svnproject project, List<Hd_svnuser> userList) {
        File outFile = new File(project.getF_path(), "/conf/passwd.http");
        StringBuffer contents = new StringBuffer();
        for (Hd_svnuser user : userList) {
            // 采用SHA加密
            // http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
            String shaPsw = "{SHA}" + EncryptUtils.encriptSHA1(EncryptUtils.decrypt(user.getF_password()));
            contents.append(user.getF_username()).append(":").append(shaPsw).append(SEP);
        }
        this.write(outFile, contents.toString());
    }

    private void exportPasswdSVN(Hd_svnproject project, List<Hd_svnuser> userList) {
        File outFile = new File(project.getF_path(), "/conf/passwd");
        StringBuffer contents = new StringBuffer();
        contents.append("[users]").append(SEP);
        for (Hd_svnuser user : userList) {
            contents.append(user.getF_username()).append("=").append(EncryptUtils.decrypt(user.getF_password())).append(SEP);// 解密
        }
        this.write(outFile, contents.toString());
    }

    /**
     * 输出权限配置文件
     * @param project
     * @param projectusergroupMap
     * @param authMap
     */
    private void exportAuthz(Hd_svnproject project, Map<String, List<Hd_svnprojectusergroup>> projectusergroupMap, Map<String, List<Hd_svnauth>> authMap) throws Exception{
        if (project == null || StringUtils.isBlank(project.getF_name())) {
            return;
        }
        File outFile = new File(project.getF_path(), "/conf/authz");
        StringBuffer contents = new StringBuffer();
        contents.append("[aliases]").append(SEP);
        contents.append("[groups]").append(SEP);
        for (Iterator<String> groupIterator = projectusergroupMap.keySet().iterator(); groupIterator.hasNext();) {
            String group = groupIterator.next();
            contents.append(group).append("=");
            List<Hd_svnprojectusergroup> projectusergroupList = projectusergroupMap.get(group);
            for (int i = 0; i < projectusergroupList.size(); i++) {
                Hd_svnprojectusergroup svnprojectusergroup = projectusergroupList.get(i);
                String userid = svnprojectusergroup.getF_userid();
                if(userid == null || "".equals(userid)) {
                    continue;
                }
                Hd_svnuser user = userService.getSvnuserById(svnprojectusergroup.getF_userid());
                if(user == null){
                    continue;
                }
                if (i != 0) {
                    contents.append(",");
                }
                contents.append(user.getF_username());
            }
            contents.append(SEP);
        }
        contents.append(SEP);

        for (Iterator<String> authIterator = authMap.keySet().iterator(); authIterator.hasNext();) {
            String rsource = authIterator.next();
            contents.append(rsource).append(SEP);
            for (Hd_svnauth auth : authMap.get(rsource)) {
                String groupId = auth.getF_groupid();
                Hd_svngroup group = groupService.getSvngroupById(groupId);
                if (group != null && StringUtils.isNotBlank(group.getF_group())) {
                    contents.append("@").append(group.getF_group()).append("=").append(auth.getF_auth()).append(SEP);
                }
            }
            contents.append(SEP);
        }
        this.write(outFile, contents.toString());
    }

    /**
     * 输出SVN方式的svnserve.conf
     * @param project
     */
    private void exportSvnConf(Hd_svnproject project){
        if (project == null || StringUtils.isBlank(project.getF_name())) {
            return;
        }
        File outFile = new File(project.getF_path(), "/conf/svnserve.conf");
        StringBuffer contents = new StringBuffer();
        contents.append("[general]").append(SEP);
        contents.append("anon-access = none").append(SEP);
        contents.append("auth-access = write").append(SEP);
        contents.append("password-db = passwd").append(SEP);
        contents.append("authz-db = authz").append(SEP);
        contents.append("[sasl]").append(SEP);
        this.write(outFile, contents.toString());
    }

    /**
     * 写文件流
     * @param outFile
     * @param contents
     */
    private void write(File outFile, String contents) {
        BufferedWriter writer = null;
        try {
            if (contents == null) {
                contents = "";
            }
            if (!outFile.getParentFile().exists()) {
                outFile.getParentFile().mkdirs();
            }
            writer = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(outFile), "UTF-8"));// UTF-8 without
            // BOM
            writer.write(contents);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            if (writer != null) {
                try {
                    writer.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
